package com.shanhai.wallpapers.fragments.wallpapers

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.paging.CombinedLoadStates
import androidx.paging.LoadState
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
import com.google.android.material.chip.Chip
import com.shanhai.wallpapers.databinding.FragmentWallpapersBinding
import com.shanhai.wallpapers.databinding.LayoutCategoriesBinding
import com.shanhai.wallpapers.extensions.applyStatusBarPadding
import org.koin.androidx.viewmodel.ext.android.viewModel

class WallpaperFragment : Fragment() {
    private var mBinding: FragmentWallpapersBinding? = null
    private val binding get() = requireNotNull(mBinding)
    private val viewModel: WallpaperViewModel by viewModel()
    private val wallpapersAdapter: WallpaperAdapter by lazy {
        WallpaperAdapter(
            itemClickListener = { photo ->
                findNavController().navigate(
                    WallpaperFragmentDirections.actionWallpaperToPreview(photo)
                )
            }
        )
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View {
        if (mBinding == null) {
            mBinding = FragmentWallpapersBinding.inflate(inflater, container, false)
            init()
        }
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.layoutHeader.applyStatusBarPadding()
    }

    private fun setListeners() {
        binding.imageSearch.setOnClickListener {
            findNavController().navigate(
                WallpaperFragmentDirections.actionWallpapersToSearch()
            )
        }

        val categoriesBinding: LayoutCategoriesBinding = binding.layoutCategories
        categoriesBinding.categoriesChipGroup.setOnCheckedStateChangeListener { _, checkedIds ->
            categoriesBinding.root.findViewById<Chip>(checkedIds.first())?.let { chip ->
                viewModel.getWallpapers(chip.text.toString())
            }
        }

        wallpapersAdapter.addLoadStateListener { loadState ->
            with(binding) {
                progressBar.isVisible = loadState.source.refresh is LoadState.Loading
                wallpaperRecyclerView.isVisible = loadState.source.refresh is LoadState.NotLoading
                if (loadState.source.refresh is LoadState.Error) {
                    textError.text = loadState.getErrorMessage()
                    layoutError.visibility = View.VISIBLE
                } else {
                    layoutError.visibility = View.GONE
                }
            }
        }
        binding.buttonRetry.setOnClickListener {
            wallpapersAdapter.retry()
        }
    }

    private fun init() {
        setListeners()
        setupWallpapersRecyclerView()
    }

    private fun setObserver() {
        viewModel.wallpapers.observe(viewLifecycleOwner) { data ->
            wallpapersAdapter.submitData(
                lifecycle = viewLifecycleOwner.lifecycle,
                pagingData = data
            )
        }
    }

    private fun removeObserver() {
        viewModel.wallpapers.removeObservers(viewLifecycleOwner)
    }

    override fun onResume() {
        super.onResume()
        setObserver()
    }

    override fun onPause() {
        super.onPause()
        removeObserver()
    }

    private fun setupWallpapersRecyclerView() {
        with(binding.wallpaperRecyclerView) {
            setHasFixedSize(true)
            itemAnimator = null
            val footerAdapter = PexelsLoadStateAdapter { wallpapersAdapter.retry() }
            adapter = wallpapersAdapter.withLoadStateFooter(footerAdapter)
            (layoutManager as GridLayoutManager).spanSizeLookup =
                object : SpanSizeLookup() {
                    override fun getSpanSize(position: Int): Int {
                        return if (position == wallpapersAdapter.itemCount && footerAdapter.itemCount > 0) {
                            GRID_SPAN_COUNT
                        } else {
                            LOADING_OR_ERROR_SPAN_COUNT
                        }
                    }
                }
        }
    }

    private fun CombinedLoadStates.getErrorMessage(): String? {
        return (source.refresh as LoadState.Error).error.localizedMessage
    }

    companion object {
        private const val GRID_SPAN_COUNT = 3
        private const val LOADING_OR_ERROR_SPAN_COUNT = 1
    }

}